import { WL_PttPayload } from 'sdk/proto/weilapb_data_define';


async function fetchWithTimeout(input: RequestInfo, init?: RequestInit, timeout?: number): Promise<Response> {
    const controller = new AbortController;
    const signal = controller.signal;
    let timerId = null as any;
    const localInit = init ? init : {} as RequestInit;
    localInit.signal = signal;

    console.log('fetch url:', input);

    const timeoutPromise = (localTimeout: number | undefined) => {
        return new Promise<Response>((resolve, reject) => {
            timerId = setTimeout(() => {
                console.log(`获取URL:${input}超时`);
                resolve(new Response("timeout", {status: 504, statusText: "timeout"}));
                controller.abort();
            }, localTimeout);
        })};

    const fetchPromise = () => {
        return new Promise<Response>((resolve, reject) => {
            console.log('输入URL', input);
            fetch(input, localInit).then(value => {
                clearTimeout(timerId);
                resolve(value);
            }).catch(reason => {
                console.error('获取失败', reason);
                reject(reason);
            })
        })};

    return Promise.race<Response>([timeoutPromise(timeout ? timeout:30000), fetchPromise()]);
}

function decompositionAudioData(pttData: Uint8Array): WL_PttPayload[] {
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = [] as WL_PttPayload[];
    let frames = 0, prevFrames = 0;
    let prevOffset = 0;

    while (offset < pttData.length) {
        const flag = pttData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(pttData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = pttData[offset] + 1;
            offset += 1;
        }

        offset += (sizeOfOpusData - 1);
        frames++;
        if ((frames + 1) % 25 == 0) {
            const payload = {} as WL_PttPayload;
            payload.frameCount = frames - prevFrames;
            payload.data = new Uint8Array(pttData.slice(prevOffset, offset));
            codedDataList.push(payload);
            prevOffset = offset;
            prevFrames = frames;
        }
    }

    if (prevOffset < offset) {
        const payload = {} as WL_PttPayload;
        payload.frameCount = frames - prevFrames;
        payload.data = new Uint8Array(pttData.slice(prevOffset, offset));
        codedDataList.push(payload);
    }

    return codedDataList;
}

function getOpusDataFrameCount(pttData: Uint8Array): number {
    let frameCount = 0;
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = null;

    while (offset < pttData.length) {
        const flag = pttData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(pttData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = pttData[offset] + 1;
            offset += 1;
        }

        offset += (sizeOfOpusData - 1);
        frameCount++;
    }

    return frameCount;
}

/**
 * 
 * @param pttData 
 * @returns 
 */
function getOpusDataListFromPttData(pttData: Uint8Array): Uint8Array[] {
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = [];

    while (offset < pttData.length) {
        if (codedDataList == null) {
            codedDataList = [];
        }
        const flag = pttData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(pttData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = pttData[offset] + 1;
            offset += 1;
        }

        const codedData = new Uint8Array(sizeOfOpusData);
        codedData[0] = flag;
        codedData.set(pttData.subarray(offset, offset + sizeOfOpusData - 1), 1);
        codedDataList.push(codedData);
        offset += (sizeOfOpusData - 1);
    }

    return codedDataList;
}

function calculateOpusDataFrame(opusData: Uint8Array): number {
    let offset = 0;
    let sizeOfOpusData = 0;
    let frameCount = 0;

    while (offset < opusData.length) {
        const flag = opusData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(opusData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = opusData[offset] + 1;
            offset += 1;
        }
        offset += (sizeOfOpusData - 1);
        frameCount++;
    }

    return frameCount;
}

async function getRunningEnvironment() {
    return new Promise((resolve, reject) => {
        let ua = navigator.userAgent.toLowerCase();
        let re = ua.match(/MicroMessenger/i)

        if (re && re[0] == "micromessenger") {
            // @ts-ignore
            wx.miniProgram.getEnv((res) => {
                if (res.miniprogram) {
                    resolve("wx_mini");
                }else {
                    resolve("wx_h5");
                }
            })
        } else {
            resolve("h5");
        }
    })
}


function get_pttdata_array_by_audiodata(audioData: Uint8Array): WL_PttPayload[] {
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = [] as WL_PttPayload[];
    let frames = 0, prevFrames = 0;
    let prevOffset = 0;

    while (offset < audioData.length) {
        const flag = audioData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(audioData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = audioData[offset] + 1;
            offset += 1;
        }

        offset += (sizeOfOpusData - 1);
        frames++;
        if ((frames + 1) % 25 == 0) {
            const payload = {} as WL_PttPayload;
            payload.frameCount = frames - prevFrames;
            payload.data = new Uint8Array(audioData.slice(prevOffset, offset));
            codedDataList.push(payload);
            prevOffset = offset;
            prevFrames = frames;
        }
    }

    if (prevOffset < offset) {
        const payload = {} as WL_PttPayload;
        payload.frameCount = frames - prevFrames;
        payload.data = new Uint8Array(audioData.slice(prevOffset, offset));
        codedDataList.push(payload);
    }

    return codedDataList;
}


export {
    fetchWithTimeout, decompositionAudioData, getOpusDataFrameCount, 
    getOpusDataListFromPttData, calculateOpusDataFrame, getRunningEnvironment,
    get_pttdata_array_by_audiodata
}